﻿using Microsoft.AspNetCore.Identity;
using SanJ.FreeCare.Abp.Authorization.Users;
using SanJ.FreeCare.Authorization.Roles;
using SanJ.FreeCare.Configuration;
using SanJ.FreeCare.Notifications;
using System;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Domain.Services;
using Volo.Abp.Identity;
using Volo.Abp.Linq;
using Volo.Abp.Settings;
using Volo.Abp.TenantManagement;

namespace SanJ.FreeCare.Authorization.Users
{
    public class UserRegistrationManager : DomainService
    {
        public IAsyncQueryableExecuter AsyncQueryableExecuter { get; set; }

        private readonly TenantManager _tenantManager;
        private readonly UserManager _userManager;
        private readonly RoleManager _roleManager;
        private readonly IUserEmailer _userEmailer;
        private readonly INotificationSubscriptionManager _notificationSubscriptionManager;
        private readonly IAppNotifier _appNotifier;
        private readonly IUserPolicy _userPolicy;
        private readonly ISettingDefinitionManager _settingDefinitionManager;
        private readonly ITenantRepository _tenantRepository;


        public UserRegistrationManager(
            TenantManager tenantManager,
            UserManager userManager,
            RoleManager roleManager,
            IUserEmailer userEmailer,
            INotificationSubscriptionManager notificationSubscriptionManager,
            IAppNotifier appNotifier,
            IUserPolicy userPolicy,
            ISettingDefinitionManager settingDefinitionManager,
            ITenantRepository tenantRepository
            )
        {
            _tenantManager = tenantManager;
            _userManager = userManager;
            _roleManager = roleManager;
            _userEmailer = userEmailer;
            _notificationSubscriptionManager = notificationSubscriptionManager;
            _appNotifier = appNotifier;
            _userPolicy = userPolicy;
            _settingDefinitionManager = settingDefinitionManager;
            _tenantRepository = tenantRepository;
        }

        public async Task<IdentityUser> RegisterAsync(string name, string emailAddress, string userName, string plainPassword, bool isEmailConfirmed, string emailActivationLink)
        {
            CheckForTenant();
            CheckSelfRegistrationIsEnabled();

            var tenant = await GetActiveTenantAsync();
            var isNewRegisteredUserActiveByDefault = await _settingDefinitionManager.GetAsync(AppSettings.UserManagement.IsNewRegisteredUserActiveByDefault);

            await _userPolicy.CheckMaxUserCountAsync(tenant.Id);

            var identityUser = new IdentityUser(GuidGenerator.Create(), userName, emailAddress, tenant.Id);
            //{
            //    TenantId = tenant.Id,
            //    Name = name,
            //    Surname = surname,
            //    EmailAddress = emailAddress,
            //    IsActive = isNewRegisteredUserActiveByDefault,
            //    UserName = userName,
            //    IsEmailConfirmed = isEmailConfirmed,
            //    Roles = new List<UserRole>()
            //};

            identityUser.Name = name;
            identityUser.SetEmailConfirmed(isEmailConfirmed);
            identityUser.SetIsActive(bool.Parse(isNewRegisteredUserActiveByDefault.DefaultValue));
            var defaultRoles = await AsyncQueryableExecuter.ToListAsync(_roleManager.Roles.Where(r => r.IsDefault));
            foreach (var defaultRole in defaultRoles)
            {
                identityUser.AddRole(defaultRole.Id);
            }

            //await _userManager.InitializeOptionsAsync(AbpSession.TenantId);
            CheckErrors(await _userManager.CreateAsync(identityUser, plainPassword));
            //await CurrentUnitOfWork.SaveChangesAsync();

            //if (!identityUser.EmailConfirmed)
            //{
            //    //未实现
            //    //identityUser.SetNewEmailConfirmationCode();
            //    await _userEmailer.SendEmailActivationLinkAsync(identityUser, emailActivationLink);
            //}

            //Notifications
            var ui = new UserIdentifier(identityUser.TenantId, identityUser.Id);
            await _notificationSubscriptionManager.SubscribeToAllAvailableNotificationsAsync(ui);
            await _appNotifier.WelcomeToTheApplicationAsync(identityUser);
            await _appNotifier.NewUserRegisteredAsync(identityUser);

            return identityUser;
        }

        private void CheckForTenant()
        {
            if (!CurrentTenant.Id.HasValue)
            {
                throw new InvalidOperationException("Can not register host users!");
            }
        }

        private async Task CheckSelfRegistrationIsEnabled()
        {
            var allowSetting = await _settingDefinitionManager.GetAsync(AppSettings.UserManagement.AllowSelfRegistration);
            bool isAllowed = false;
            if (allowSetting != null) bool.TryParse(allowSetting.DefaultValue, out isAllowed);

            if (!isAllowed)
            {
                throw new UserFriendlyException("SelfUserRegistrationIsDisabledMessage_Detail");
            }
        }

        private async Task<bool> UseCaptchaOnRegistration()
        {
            var allowSetting = await _settingDefinitionManager.GetAsync(AppSettings.UserManagement.UseCaptchaOnRegistration);
            bool isAllowed = false;
            if (allowSetting != null) bool.TryParse(allowSetting.DefaultValue, out isAllowed);

            return isAllowed;
        }

        private async Task<Tenant> GetActiveTenantAsync()
        {
            if (!CurrentTenant.Id.HasValue)
            {
                return null;
            }

            return await GetActiveTenantAsync(CurrentTenant.Id.Value);
        }

        private async Task<Tenant> GetActiveTenantAsync(Guid tenantId)
        {
            var tenant = await _tenantRepository.FindAsync(tenantId);
            if (tenant == null)
            {
                throw new UserFriendlyException("UnknownTenantId{0}");
                //throw new UserFriendlyException(L("UnknownTenantId{0}", tenantId));
            }

            if (tenant.IsDeleted)
            {
                throw new UserFriendlyException("TenantIdIsNotActive{0}");
                //throw new UserFriendlyException(L("TenantIdIsNotActive{0}", tenantId));
            }

            return tenant;
        }

        protected virtual void CheckErrors(IdentityResult identityResult)
        {
            identityResult.CheckErrors();
        }
    }
}
